package com.hiwan.system.security.realm;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.Permission;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.hiwan.platform.utils.Encodes;
import com.hiwan.platform.utils.EncryptUtil;
import com.hiwan.platform.utils.StringUtils;
import com.hiwan.system.common.security.session.SessionDAO;
import com.hiwan.system.dao.org.OrgDao;
import com.hiwan.system.dao.user.UserDao;
import com.hiwan.system.pojo.MenuInfo;
import com.hiwan.system.pojo.OrgInfo;
import com.hiwan.system.pojo.RoleInfo;
import com.hiwan.system.pojo.UserInfo;
import com.hiwan.system.security.UsernamePasswordToken;
import com.hiwan.system.util.DictCacheUtils;
import com.hiwan.system.util.UserCacheUtils;

/**
 * 
 * Datetime   ： 2016年1月4日 下午2:41:07<br>
 * Title      :  SystemAuthorizingRealm.java<br>
 * Description:   系统安全认证实现类<br>
 * Company    :  hiwan<br>
 * @author cbj
 *
 */

public class SystemAuthorizingRealm extends AuthorizingRealm {

	private Logger logger = LoggerFactory.getLogger(SystemAuthorizingRealm.class);

	@Resource(name = "userDao")
	private UserDao userDao;
	@Autowired
	private SessionDAO sessionDAO;
	@Autowired
	private OrgDao orgDao;
	
	/**
	 * 认证回调函数, 登录时调用
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) {
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;

		int activeSessionSize = sessionDAO.getActiveSessions(false).size();
		logger.debug("login submit, active session size: {}, username: {}", activeSessionSize, token.getUsername());

		// 校验登录验证码
		/*
		 * if (LoginController.isValidateCodeLogin(token.getUsername(), false, false)){ Session session =
		 * UserCacheUtils.getSession(); String code = (String)session.getAttribute(ValidateCodeServlet.VALIDATE_CODE);
		 * if (token.getCaptcha() == null || !token.getCaptcha().toUpperCase().equals(code)){ throw new
		 * AuthenticationException("msg:验证码错误, 请重试."); } }
		 */

		if (StringUtils.isBlank(token.getUsername()) || StringUtils.isBlank(String.valueOf(token.getPassword()))) {
			throw new AuthenticationException("msg:请输入用户名或密码");
		}

		// 校验用户名密码
		UserInfo u = new UserInfo(token.getUsername());
		UserInfo user = userDao.selectUser(u);
		
		if (user != null) {
			if (!StringUtils.equals(user.getStatus(), "1")) {
				String status = DictCacheUtils.getDictValue(user.getStatus(), "D00026");
				throw new AuthenticationException("msg:该帐号的状态为【" + status + "】，禁止登录.");
			}
			
			OrgInfo tempO = orgDao.selectOrgInfo(user.getOrgId());
			if(StringUtils.equals(tempO.getStatus(), "2")){
				String status = DictCacheUtils.getDictValue(tempO.getStatus(), "D00027");
				throw new AuthenticationException("msg:该帐号所在机构状态为【" + status + "】，禁止登录.");
			}
			
			List<RoleInfo> roles = userDao.selectUserRoles(u);
			if(roles == null || roles.isEmpty()){
				throw new AuthenticationException("msg:该用户未分配任何可用角色权限.");
			}

			byte[] salt = Encodes.decodeHex(user.getUserPwd().substring(0, 16));
			return new SimpleAuthenticationInfo(new Principal(user, token.isMobileLogin()),
					user.getUserPwd().substring(16), ByteSource.Util.bytes(salt), getName());
		} else{
			return null;
		}
		
	}

	/**
	 * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		Principal principal = (Principal) getAvailablePrincipal(principals);
		UserInfo user = UserCacheUtils.get(principal.getId());
		if (user != null) {
			SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

			// 添加用户角色信息
			for (RoleInfo role : user.getRoles()) {
				info.addRole(role.getRoleId());
			}

			List<MenuInfo> list = UserCacheUtils.getMenuList();
			for (MenuInfo menu : list) {
				if (StringUtils.isNotBlank(menu.getPermission())) {
					// 添加基于Permission的权限信息
					for (String permission : StringUtils.split(menu.getPermission(), ",")) {
						info.addStringPermission(permission);
					}
				}
			}
			return info;
		} else {
			return null;
		}
	}

	@Override
	protected void checkPermission(Permission permission, AuthorizationInfo info) {
		authorizationValidate(permission);
		super.checkPermission(permission, info);
	}

	@Override
	protected boolean[] isPermitted(List<Permission> permissions, AuthorizationInfo info) {
		if (permissions != null && !permissions.isEmpty()) {
			for (Permission permission : permissions) {
				authorizationValidate(permission);
			}
		}
		return super.isPermitted(permissions, info);
	}

	@Override
	public boolean isPermitted(PrincipalCollection principals, Permission permission) {
		authorizationValidate(permission);
		return super.isPermitted(principals, permission);
	}

	@Override
	protected boolean isPermittedAll(Collection<Permission> permissions, AuthorizationInfo info) {
		if (permissions != null && !permissions.isEmpty()) {
			for (Permission permission : permissions) {
				authorizationValidate(permission);
			}
		}
		return super.isPermittedAll(permissions, info);
	}

	/**
	 * 授权验证方法
	 * @param permission
	 */
	private void authorizationValidate(Permission permission) {
		// 模块授权预留接口
	}

	/**
	 * 设定密码校验的Hash算法与迭代次数
	 */
	@PostConstruct
	public void initCredentialsMatcher() {
		HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(EncryptUtil.HASH_ALGORITHM);
		matcher.setHashIterations(EncryptUtil.HASH_INTERATIONS);
		setCredentialsMatcher(matcher);
	}

	/**
	 * 清空用户关联权限认证，待下次使用时重新加载
	 */
	public void clearCachedAuthorizationInfo(Principal principal) {
		PrincipalCollection principals = new SimplePrincipalCollection(principal, getName());
		clearCachedAuthorizationInfo(principals);
	}

	/**
	 * 清空所有关联认证
	 */
	public void clearAllCachedAuthorizationInfo() {
		Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
		if (cache != null) {
			cache.clear();
		}
	}

	/**
	 * 授权用户信息
	 */
	public static class Principal implements Serializable {

		private static final long serialVersionUID = 1L;

		private String id; // 编号
		private String userName; // 登录名
		private boolean mobileLogin; // 是否手机登录

		public Principal(UserInfo user, boolean mobileLogin) {
			this.id = user.getUserId();
			this.userName = user.getUserName();
			this.mobileLogin = mobileLogin;
		}

		public String getId() {
			return id;
		}

		public String getUserName() {
			return userName;
		}

		public boolean isMobileLogin() {
			return mobileLogin;
		}

		/**
		 * 获取SESSIONID
		 */
		public String getSessionid() {
			try {
				return (String) UserCacheUtils.getSession().getId();
			} catch (Exception e) {
				return "";
			}
		}

		@Override
		public boolean equals(Object obj) {
			if (obj == this)
				return true;
			if (!(obj instanceof Principal))
				return false;
			Principal principal = (Principal) obj;
			return principal.id.equals(id) && principal.userName.equals(userName);
		}

		@Override
		public int hashCode() {
			int result = 17;
			result = 37 * result + userName.hashCode();
			result = 37 * result + id.hashCode();
			return result;
		}

		@Override
		public String toString() {
			return id;
		}

	}
}
